package com.jxtc.enterprise.hr.service;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.common.constants.FoodMenuMakerEnum;
import com.jxtc.enterprise.common.constants.FoodMenuStatus;
import com.jxtc.enterprise.common.entity.*;
import com.jxtc.enterprise.common.enums.ShowVipUserFoodEnum;
import com.jxtc.enterprise.common.exception.InsertFailureException;
import com.jxtc.enterprise.common.exception.ModifyFailureException;
import com.jxtc.enterprise.common.exception.UserAlreadyExistException;
import com.jxtc.enterprise.common.mapper.*;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import com.jxtc.enterprise.hr.dto.*;
import com.jxtc.enterprise.hr.vo.EmployeeVO;
import com.jxtc.enterprise.hr.vo.req.CompanyIdAndDepartmentIdReqVo;
import com.jxtc.enterprise.hr.vo.req.EmployeeBindCompanyReqVo;
import com.jxtc.enterprise.hr.vo.req.UserOtherCompRelationCreateRespVo;
import com.jxtc.enterprise.hr.vo.resp.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class HrEmployeeManagementService {

    private final UserMapper userMapper;
    private final UserOtherCompRelationMapper userOtherCompRelationMapper;
    private final DepartmentMapper departmentMapper;
    private final CompanyMapper companyMapper;
    private final FoodMenuMapper foodMenuMapper;
    private final BCryptPasswordEncoder passwordEncoder;

    /**
     * 根据公司 ID 分页查询员工信息，如果 name 字段不为空，则按照姓名进行模糊查询后分页
     *
     * @param companyId 公司 ID
     * @param name      员工姓名模糊查询的关键词
     * @param current   当前页数
     * @param size      每页展示数据数量
     */
    public PaginationResponseVO<EmployeeVO> pageByName(String companyId, String name, int current, int size) {
        // 分页查询第 current 页的 size 条数据
        Page<EmployeeDepartmentDTO> page = new Page<>(current, size);

        Page<EmployeeDepartmentDTO> result = userMapper.queryEmployeeWithDepartmentByCompanyIdAndName(page, companyId, name);
        List<EmployeeVO> records = result.getRecords().stream().map(EmployeeVO::new).collect(Collectors.toList());

        List<String> employeeIdList = result.getRecords().stream().map(EmployeeDepartmentDTO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(employeeIdList)) {
            LambdaQueryWrapper<UserOtherCompRelation> userOtherCompRelationQueryWrapper = new LambdaQueryWrapper<UserOtherCompRelation>()
                    .in(UserOtherCompRelation::getUserId, employeeIdList)
                    .eq(UserOtherCompRelation::getDelFlag, false);
            List<UserOtherCompRelation> userOtherCompRelationList = userOtherCompRelationMapper.selectList(userOtherCompRelationQueryWrapper);
            List<String> companyIdList = userOtherCompRelationList.stream()
                    .map(UserOtherCompRelation::getOtherCompanyId)
                    .distinct()
                    .collect(Collectors.toList());
            List<String> departmentIdList = userOtherCompRelationList.stream()
                    .map(UserOtherCompRelation::getDepartmentId)
                    .distinct()
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(companyIdList) && CollectionUtils.isNotEmpty(departmentIdList)) {
                LambdaQueryWrapper<Company> companyQueryWrapper = new LambdaQueryWrapper<Company>().in(Company::getId, companyIdList);
                List<Company> companyList = companyMapper.selectList(companyQueryWrapper);

                LambdaQueryWrapper<Department> departmentQueryWrapper = new LambdaQueryWrapper<Department>().in(Department::getId, departmentIdList);
                List<Department> departmentList = departmentMapper.selectList(departmentQueryWrapper);

                Map<String, String> companyIdToNameMap = companyList.stream().collect(Collectors.toMap(Company::getId, Company::getName));
                Map<String, String> departmentIdToNameMap = departmentList.stream().collect(Collectors.toMap(Department::getId, Department::getName));
                Map<String, List<UserOtherCompRelation>> employeeIdToCompanyListMap = userOtherCompRelationList.stream().collect(Collectors.groupingBy(UserOtherCompRelation::getUserId));

                for (EmployeeVO employeeVO : records) {
                    String employeeId = employeeVO.getId();

                    List<UserOtherCompRelation> canOrderFoodCompanyList = employeeIdToCompanyListMap.get(employeeId);
                    if (CollectionUtils.isNotEmpty(canOrderFoodCompanyList)) {
                        String otherCanOrderFoodCompanyName = canOrderFoodCompanyList.stream()
                                // 将公司 ID 和部门 ID 转换为 "公司名称 (部门名称)" 格式
                                .map(comp -> formatOtherCanOrderFoodCompanyName(comp.getOtherCompanyId(), comp.getDepartmentId(), companyIdToNameMap, departmentIdToNameMap))
                                .collect(Collectors.joining(", "));
                        employeeVO.setOtherCanOrderFoodCompanyName(otherCanOrderFoodCompanyName);
                    }
                }
            }
        }

        return new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);
    }

    private String formatOtherCanOrderFoodCompanyName(String companyId, String departmentId, Map<String, String> companyIdToNameMap, Map<String, String> departmentIdToNameMap) {
        // 公司 ID 对应的公司名称不存在时，显示未知，尽早暴露数据不一致问题，部门名称同理
        String companyName = companyIdToNameMap.getOrDefault(companyId, "未知公司名称");
        String departmentName = departmentIdToNameMap.getOrDefault(departmentId, "未知部门名称");

        // 返回格式如下：
        // 公司名称 (部门名称)
        return String.format("%s (%s)", companyName, departmentName);
    }

    /**
     * 新增员工信息，并按照姓名 + 部门 + 手机号进行唯一识别，防止重复录入（新增员工的密码默认 123456）
     *
     * @param dto 前端传递过来的员工信息
     */
    public void saveEmployee(EmployeeDTO dto) {
        // 前端传递的公司 ID 不存在时，给出提示信息
        Company company = companyMapper.selectById(dto.getCompanyId());
        if (company == null) {
            throw new IllegalArgumentException("新增员工信息失败，公司 ID 不存在");
        }

        // 前端传递的部门 ID 不存在时，给出提示信息
        Department department = departmentMapper.selectById(dto.getDepartmentId());
        if (department == null) {
            throw new IllegalArgumentException("新增员工信息失败，部门 ID 不存在");
        }

        // 使用手机号作为唯一识别，如果员工已存在给出提示信息，防止重复录入员工信息
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("phone_number", dto.getPhoneNumber());
        wrapper.eq("del_flag", 0);
        List<User> users = userMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(users)) {
            List<String> duplicatedPhoneUserNames = users.stream().map(User::getUsername).collect(Collectors.toList());
            List<String> duplicatedCompanyIds = users.stream().map(User::getCompanyId).distinct().collect(Collectors.toList());
            List<Company> duplicatedCompanyList = companyMapper.selectList(new LambdaQueryWrapper<Company>().in(Company::getId, duplicatedCompanyIds));
            List<String> duplicatedCompanyNames = duplicatedCompanyList.stream().map(Company::getName).collect(Collectors.toList());
            String msg = MessageFormat.format("该手机号用户已录入在公司: {0}, 用户姓名: {1}，请勿重复录入", duplicatedCompanyNames.toString(), duplicatedPhoneUserNames.toString());
            throw new UserAlreadyExistException(msg);
        }

        // 获取菜单 ID
        String menuId = queryMenuId(company.getId());

        User employee = new User();
        employee.setUsername(dto.getName());
        employee.setCompanyId(dto.getCompanyId());
        employee.setDepartmentId(dto.getDepartmentId());
        employee.setPhoneNumber(dto.getPhoneNumber());
        // 默认初始密码为 123456
        // employee.setPasswd(passwordEncoder.encode("123456")); // 暂时不加密
        employee.setPasswd("123456");
        // 如果前端传递的密码，则设置密码
        if (dto.getPassword() != null && !dto.getPassword().isEmpty()) {
            employee.setPasswd(dto.getPassword());
        }
        employee.setMenuId(menuId);
        // 设置员工每餐的点餐限购份数
        employee.setLimitCount(dto.getLimitCount());

        // 新增员工信息时，使用公司表中配置的是否显示客户餐作为默认值
        employee.setShowVipFoodBtn(company.getShowVipUserFoodBtn());

        if (userMapper.insert(employee) > 0) {
            return;
        }

        throw new ModifyFailureException("新增员工失败，请稍后重试");
    }

    /**
     * 按照员工 ID 编辑员工信息
     *
     * @param dto 前端传递过来包含员工 ID 的员工信息
     */
    public void updateEmployee(EmployeeUpdateDTO dto) {
        // 前端传递的部门 ID 不存在时，给出提示信息
        Department department = departmentMapper.selectById(dto.getDepartmentId());
        if (department == null) {
            throw new IllegalArgumentException("修改员工信息失败，部门 ID 不存在");
        }

        User employee = new User();
        employee.setId(dto.getId());
        employee.setUsername(dto.getName());
        employee.setDepartmentId(dto.getDepartmentId());
        employee.setPhoneNumber(dto.getPhoneNumber());
        // 修改员工每餐的点餐限购份数
        employee.setLimitCount(dto.getLimitCount());

        // 修改员工密码
        if (dto.getPassword() != null && !dto.getPassword().isEmpty()) {
            employee.setPasswd(dto.getPassword());
        }

        // 修改员工是否显示客户餐点餐按钮
        if (dto.getShowVipUserFoodBtn() != null) {
            int showVipUserFoodBtn = dto.getShowVipUserFoodBtn() ? ShowVipUserFoodEnum.SHOW_VIP_USER_FOOD.getValue() : ShowVipUserFoodEnum.HIDE_VIP_USER_FOOD.getValue();
            employee.setShowVipFoodBtn(showVipUserFoodBtn);
        }

        if (userMapper.updateById(employee) > 0) {
            return;
        }

        throw new ModifyFailureException("修改员工信息失败，请稍后重试");
    }

    /**
     * 对指定员工进行充值
     */
    @Transactional(rollbackFor = ModifyFailureException.class)
    public void rechargeEmployee(RechargeDTO dto) {
        List<String> employeeIds = dto.getEmployeeIds();
        int amount = dto.getAmount().multiply(new BigDecimal("100")).intValue();

        // 批量查询 employeeIds 中存在的员工
        List<User> savedEmployees = userMapper.selectBatchIds(employeeIds);

        // TODO: 考虑是否使用 Mapper XML 实现批量更新来优化以下操作
        for (User savedEmployee : savedEmployees) {
            User employee = new User();
            employee.setId(savedEmployee.getId());
            // 为该员工充值 amount 金额
            employee.setBalance(savedEmployee.getBalance() + amount);

            // 更新数据库中的员工信息，如果更新失败，抛出异常并回滚数据
            if (userMapper.updateById(employee) <= 0) {
                throw new ModifyFailureException("充值失败，请稍后重试");
            }
        }
    }

    /**
     * 根据公司 ID 对该公司未标记删除的员工进行批量充值
     */
    @Transactional(rollbackFor = ModifyFailureException.class)
    public void rechargeEmployeeByCompanyId(BatchRechargeDTO dto) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("company_id", dto.getCompanyId());
        wrapper.eq("del_flag", 0);
        List<User> savedEmployees = userMapper.selectList(wrapper);

        int amount = dto.getAmount().multiply(new BigDecimal("100")).intValue();

        for (User savedEmployee : savedEmployees) {
            User employee = new User();
            employee.setId(savedEmployee.getId());
            // 为该员工充值 amount 金额
            employee.setBalance(savedEmployee.getBalance() + amount);

            // 更新数据库中的员工信息，如果更新失败，抛出异常并回滚数据
            if (userMapper.updateById(employee) <= 0) {
                throw new ModifyFailureException("充值失败，请稍后重试");
            }
        }
    }

    /**
     * 根据公司 ID，将上传的 Excel 文件中的员工信息导入到数据库中。
     * - 如果 Excel 文件中填写的部门名称在数据库中不存在，则创建该部门，取餐地址默认公司地址
     * - 按照姓名 + 部门 + 手机号进行唯一识别，如果数据库中有该员工信息，则不进行导入
     * - 导入员工的密码默认 123456
     *
     * @param companyId 公司 ID
     * @param rows      Excel 文件的每行数据
     */
    public void saveEmployeeByExcel(String companyId, List<List<Object>> rows) {
        Company company = companyMapper.selectById(companyId);
        if (company == null) {
            throw new IllegalArgumentException("导入员工失败，公司 ID 不存在");
        }

        // 获取菜单 ID
        String menuId = queryMenuId(company.getId());

        // 先获取公司下的所有部门，用 excel 中的部门名称进行一一匹配找到对应的部门 ID
        QueryWrapper<Department> departmentQueryWrapper = new QueryWrapper<>();
        departmentQueryWrapper.eq("company_id", companyId);
        List<Department> departments = departmentMapper.selectList(departmentQueryWrapper);

        Map<String, String> departmentNameToIdMap = mapDepartmentNameToId(departments);

        // 获取该公司所有已经录入的员工信息
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("company_id", companyId);
        userQueryWrapper.eq("del_flag", 0);
        List<User> users = userMapper.selectList(userQueryWrapper);

        Set<String> uniqueIdentitySet = getUniqueIdentitySet(users);

        for (List<Object> row : rows) {
            if (row.size() != 3) {
                // 数据不完整，跳过该行数据
                continue;
            }

            String username = String.valueOf(row.get(0)).trim();
            String departmentName = String.valueOf(row.get(1)).trim();
            String phoneNumber = String.valueOf(row.get(2)).trim();

            // 将部门名称转换为对应的部门 ID，如果该名称对应的部门不存在，默认为 null
            String departmentId = departmentNameToIdMap.getOrDefault(departmentName, null);
            if (departmentId == null) {
                // 部门不存在，创建部门
                Department department = new Department();
                department.setCompanyId(companyId);
                department.setName(departmentName);
                // 这种情况下，取餐地址默认为该公司地址
                department.setAddress(company.getAddress());
                if (departmentMapper.insert(department) <= 0) {
                    // 日志记录一下新增部门失败的数据
                    log.error("导入员工信息时新增部门失败，部门信息：{}", department);
                }
                // 获取自动生成的部门 ID
                departmentId = department.getId();
                // 将新创建的部门名称和部门 ID 存入 map 中，防止创建同名部门
                departmentNameToIdMap.put(departmentName, departmentId);
            }

            String identity = getUniqueIdentity(username, departmentId, phoneNumber);

            // 如果该员工已经存在，则跳过导入该行数据
            if (uniqueIdentitySet.contains(identity)) {
                continue;
            }

            // 创建新员工信息
            User employee = new User();
            employee.setUsername(username);
            employee.setCompanyId(companyId);
            employee.setDepartmentId(departmentId);
            employee.setPhoneNumber(phoneNumber);
            // 默认初始密码为 123456
            // employee.setPasswd(passwordEncoder.encode("123456")); // 暂时不加密
            employee.setPasswd("123456");
            employee.setMenuId(menuId);

            // 新增员工信息时，使用公司表中配置的是否显示客户餐作为默认值
            employee.setShowVipFoodBtn(company.getShowVipUserFoodBtn());

            if (userMapper.insert(employee) <= 0) {
                // 日志记录一下导入失败的数据
                log.error("导入员工信息失败，员工信息：{}", employee);
            }
        }
    }

    /**
     * 根据员工 ID 软删除员工
     *
     * @param id 员工 ID
     */
    public void deleteEmployeeById(String id) {
        User employee = new User();
        employee.setId(id);
        employee.setDelFlag(true);

        if (userMapper.updateById(employee) <= 0) {
            throw new ModifyFailureException("删除员工失败，id 为 " + id + " 的员工不存在");
        }
    }

    /**
     * 根据员工 ID 清空员工余额
     *
     * @param id 员工 ID
     */
    public void clearEmployeeBalanceById(String id) {
        User employee = new User();
        employee.setId(id);
        employee.setBalance(0);

        if (userMapper.updateById(employee) <= 0) {
            throw new ModifyFailureException("清空员工余额失败，id 为 " + id + " 的员工不存在");
        }
    }

    /**
     * 根据公司 ID 查询该公司当前配置的最新的菜单 ID
     *
     * @param companyId 公司 ID
     * @return 菜单 ID
     */
    private String queryMenuId(String companyId) {
        // SELECT menu_id FROM food_menu WHERE company_id = '' AND del_flag = 0 AND `status` = 1 AND marker = 1 ORDER BY CREATE_TIME DESC;
        QueryWrapper<FoodMenu> foodMenuQueryWrapper = new QueryWrapper<>();
        foodMenuQueryWrapper.eq("del_flag", 0);
        foodMenuQueryWrapper.eq("status", FoodMenuStatus.ACTIVE.getStatus());
        foodMenuQueryWrapper.eq("marker", FoodMenuMakerEnum.MENU_MARKER.getCode());
        foodMenuQueryWrapper.eq("company_id", companyId);
        foodMenuQueryWrapper.orderByDesc("create_time");

        // 如果存在，获取第一个；如果不存在，menu_id 赋值为 ''
        return foodMenuMapper.selectList(foodMenuQueryWrapper)
                .stream()
                .map(FoodMenu::getMenuId)
                .distinct()
                .findFirst()
                .orElse("");
    }

    /**
     * 将部门名称转换为对应的部门 ID
     *
     * @param departments 部门信息列表
     * @return 部门名称到部门 ID 的映射
     */
    private Map<String, String> mapDepartmentNameToId(List<Department> departments) {
        return departments.stream().collect(Collectors.toMap(Department::getName, Department::getId));
    }

    /**
     * 获取所有已经录入的员工信息的唯一识别
     *
     * @param users 员工信息列表
     * @return 唯一识别集合
     */
    private Set<String> getUniqueIdentitySet(List<User> users) {
        return users.stream().map(this::getUniqueIdentity).collect(Collectors.toSet());
    }

    /**
     * 按照姓名 + 部门 + 手机号进行唯一识别
     *
     * @param user 用户信息
     * @return 唯一识别
     */
    private String getUniqueIdentity(User user) {
        return getUniqueIdentity(user.getUsername(), user.getDepartmentId(), user.getPhoneNumber());
    }

    /**
     * 后续如果要修改唯一识别规则，修改该方法即可
     */
    private String getUniqueIdentity(String username, String departmentId, String phoneNumber) {
        return username + departmentId + phoneNumber;
    }

    public int batchEditEmployeeFoodLimitCount(String companyId, List<String> employeeIds, int limitCount) {

        int updatedCount = userMapper.batchUpdateEmployeeLimitCount(companyId, employeeIds, limitCount);
        return updatedCount;
    }

    public void exportAllEmployeeInfo2Excel(String companyId, HttpServletResponse response) {

        Company company = companyMapper.selectById(companyId);
        if (company == null) {
            log.error("companyId: {} 不存在", companyId);
        }

        LambdaQueryWrapper<Company> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select().eq(Company::getId, companyId).eq(Company::getDelFlag, false);
        List<HashMap<String, Object>> employeeInfos = userMapper.queryAllCompanyEmployeeInfos(companyId);

        ExcelWriter writer = ExcelUtil.getWriter(true);
        int idx = 1;
        List<Map<String, Object>> data = new ArrayList<>();
        for (HashMap<String, Object> employeeInfo : employeeInfos) {
            String employeeName = (String) employeeInfo.getOrDefault("employeeName", "员工");
            String employeeDepartmentName = (String) employeeInfo.getOrDefault("departmentName", "部分");
            String phone = (String) employeeInfo.getOrDefault("phone", "unknown");
            int limitCount = (int) employeeInfo.getOrDefault("limitCount", 1);
            data.add(createRow(idx++, employeeName, employeeDepartmentName, phone, limitCount));
        }

        addSheet(writer, data);
        String filename = MessageFormat.format("{0}-员工名录-{1}.xlsx", company.getName(), String.valueOf(System.currentTimeMillis()));
        try {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));

            writer.flush(response.getOutputStream(), true);
        } catch (IOException ex) {
            log.error("写入excel文件异常，msg: {0}", ex);
        }
    }


    private void addSheet(ExcelWriter writer, List<Map<String, Object>> data) {

        writer.write(data, true);

        // 获取当前工作表
        Sheet sheet = writer.getSheet();

        // 设置“姓名”这一列的宽度，索引从 0 开始
        int employeeNameColumnIndex = 1;
        sheet.setColumnWidth(employeeNameColumnIndex, 20 * 256);

        // 设置“姓名”这一列的宽度，索引从 0 开始
        int departmentColumnIndex = 2;
        sheet.setColumnWidth(departmentColumnIndex, 40 * 256);

        // 设置“手机号”这一列的宽度，索引从 0 开始
        int phoneColumnIndex = 3;
        sheet.setColumnWidth(phoneColumnIndex, 40 * 256);
    }

    private Map<String, Object> createRow(Integer index, String employeeName, String department, String phone,
                                          int limitCount) {
        // 使用 LinkedHashMap 而不是 HashMap 防止标题栏乱序
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("序号", index);
        row.put("姓名", employeeName);
        row.put("部门", department);
        row.put("手机号", phone);
        row.put("限购分数", limitCount);
        return row;
    }


    public List<UserOtherCompanyRelationRespVo> queryCompanyAndDepartmentListByEmployeeId(String employeeId) {
        LambdaQueryWrapper<UserOtherCompRelation> userOtherCompRelationQueryWrapper = new LambdaQueryWrapper<UserOtherCompRelation>()
                .eq(UserOtherCompRelation::getUserId, employeeId)
                .eq(UserOtherCompRelation::getDelFlag, false);
        List<UserOtherCompRelation> userOtherCompRelationList = userOtherCompRelationMapper.selectList(userOtherCompRelationQueryWrapper);

        if (CollectionUtils.isEmpty(userOtherCompRelationList)) {
            // 如果当前员工尚未绑定其它可点餐公司，直接返回空列表接口
            return Collections.emptyList();
        }

        // 其它可点餐公司不为空时，公司 ID 列表和部门 ID 列表应该一定不为空
        List<String> otherCompanyIdList = userOtherCompRelationList.stream().map(UserOtherCompRelation::getOtherCompanyId).collect(Collectors.toList());
        List<String> departmentIdList = userOtherCompRelationList.stream().map(UserOtherCompRelation::getDepartmentId).collect(Collectors.toList());

        List<Company> companyList = companyMapper.selectBatchIds(otherCompanyIdList);
        List<Department> departmentList = departmentMapper.selectBatchIds(departmentIdList);

        // 按照公司 ID 进行分组，方便后续根据公司 ID 获取公司名称
        Map<String, Company> companyMap = companyList.stream().collect(Collectors.toMap(Company::getId, Function.identity()));
        // 按照部门 ID 进行分组，方便后续根据部门 ID 获取部门名称
        Map<String, Department> departmentMap = departmentList.stream().collect(Collectors.toMap(Department::getId, Function.identity()));

        // 将查询结果转换为响应对象列表
        List<UserOtherCompanyRelationRespVo> voList = new ArrayList<>(userOtherCompRelationList.size());
        for (UserOtherCompRelation userOtherCompRelation : userOtherCompRelationList) {
            UserOtherCompanyRelationRespVo vo = new UserOtherCompanyRelationRespVo();
            vo.setUserOtherCompRelationId(userOtherCompRelation.getId());
            vo.setCompanyId(userOtherCompRelation.getOtherCompanyId());
            vo.setDepartmentId(userOtherCompRelation.getDepartmentId());

            Company company = companyMap.get(userOtherCompRelation.getOtherCompanyId());
            String defaultCompanyName = "未知";
            if (company != null) {
                defaultCompanyName = company.getName();
            }
            vo.setCompanyName(defaultCompanyName);

            Department department = departmentMap.get(userOtherCompRelation.getDepartmentId());
            String defaultDepartmentName = "未知";
            if (department != null) {
                defaultDepartmentName = department.getName();
            }
            vo.setDepartmentName(defaultDepartmentName);

            voList.add(vo);
        }

        return voList;
    }


    public List<CompanyWithDepartmentInfoRespVo> queryOtherCompanyAndDepartmentByCompanyIdAndEmployeeId(String companyId, String employeeId) {
        Company company = companyMapper.selectById(companyId);
        if (company == null) {
            // 如果前端传递的公司 ID 在后端查不到，直接返回空列表即可
            return Collections.emptyList();
        }

        // 查询当前员工已经绑定的其它可点餐公司的 ID 列表
        LambdaQueryWrapper<UserOtherCompRelation> userOtherCompRelationQueryWrapper = new LambdaQueryWrapper<UserOtherCompRelation>()
                .eq(UserOtherCompRelation::getUserId, employeeId)
                .eq(UserOtherCompRelation::getDelFlag, false)
                .select(UserOtherCompRelation::getOtherCompanyId);
        List<String> companyIdBindedList = userOtherCompRelationMapper.selectObjs(userOtherCompRelationQueryWrapper);

        String tenantId = company.getTenantId();

        LambdaQueryWrapper<Company> companyQueryWrapper = new LambdaQueryWrapper<Company>()
                .eq(Company::getTenantId, tenantId)
                // 排除当前公司，只查询租户关联的其它未删除公司信息
                .ne(Company::getId, companyId)
                .eq(Company::getDelFlag, false);
        if (CollectionUtils.isNotEmpty(companyIdBindedList)) {
            // 如果当前员工已经绑定了其它可点餐公司，则查询其它可点餐公司时，排除已经绑定的公司
            companyQueryWrapper.notIn(Company::getId, companyIdBindedList);
        }

        List<Company> companyList = companyMapper.selectList(companyQueryWrapper);
        if (CollectionUtils.isEmpty(companyList)) {
            // 如果当前租户没有其它公司，直接返回空列表即可
            return Collections.emptyList();
        }

        List<String> companyIdList = companyList.stream().map(Company::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Department> departmentQueryWrapper = new LambdaQueryWrapper<Department>()
                .in(Department::getCompanyId, companyIdList);
        List<Department> departmentList = departmentMapper.selectList(departmentQueryWrapper);
        if (CollectionUtils.isEmpty(departmentList)) {
            // 正常情况下，如果 companyIdList 不为空，则一定有部门信息，如果为空，则表示出现了数据不一致的情况，日志记录一下
            log.error("queryOtherCompanyAndDepartmentByCompanyIdAndEmployeeId, departmentList is empty, companyIdList:{}", companyIdList);
            departmentList = Collections.emptyList();
        }

        // 根据公司 ID 将部门信息进行分组
        Map<String, List<Department>> companyIdToDepartmentListMap = departmentList.stream().collect(Collectors.groupingBy(Department::getCompanyId));

        // 将查询结果转换为响应对象列表
        List<CompanyWithDepartmentInfoRespVo> voList = new ArrayList<>(companyList.size());
        for (Company comp : companyList) {
            CompanyWithDepartmentInfoRespVo vo = new CompanyWithDepartmentInfoRespVo();

            vo.setCompanyId(comp.getId());
            vo.setCompanyName(comp.getName());

            List<Department> deptList = companyIdToDepartmentListMap.getOrDefault(comp.getId(), Collections.emptyList());
            List<DepartmentInfoRespVo> deptVoList = new ArrayList<>(deptList.size());
            for (Department dept : deptList) {
                DepartmentInfoRespVo deptVo = new DepartmentInfoRespVo();
                deptVo.setDepartmentId(dept.getId());
                deptVo.setDepartmentName(dept.getName());
                deptVoList.add(deptVo);
            }
            vo.setDepartmentList(deptVoList);

            voList.add(vo);
        }

        return voList;
    }


    @Transactional(rollbackFor = Exception.class)
    public void bindCompanyAndDepartmentForEmployee(EmployeeBindCompanyReqVo reqVo) {
        String employeeId = reqVo.getEmployeeId();
        User user = userMapper.selectById(employeeId);
        if (user == null) {
            // 如果前端传递过来的员工 ID 在数据库中找不到，直接返回错误提示信息即可
            log.warn("bindCompanyAndDepartmentForEmployee, employee not exist, employeeId: {}", employeeId);
            throw new IllegalArgumentException("ID 为 " + employeeId + " 的员工信息不存在");
        }

        List<CompanyIdAndDepartmentIdReqVo> list = reqVo.getCompanyAndDepartmentIdList();
        if (list == null || list.isEmpty()) {
            // 如果前端传递过来的公司 ID 列表为空，直接返回即可，不需要做任何操作
            return;
        }

        for (CompanyIdAndDepartmentIdReqVo companyIdAndDepartmentIdReqVo : reqVo.getCompanyAndDepartmentIdList()) {
            UserOtherCompRelation userOtherCompRelation = new UserOtherCompRelation();
            userOtherCompRelation.setUserId(employeeId);
            userOtherCompRelation.setOtherCompanyId(companyIdAndDepartmentIdReqVo.getCompanyId());
            userOtherCompRelation.setDepartmentId(companyIdAndDepartmentIdReqVo.getDepartmentId());

            LambdaQueryWrapper<UserOtherCompRelation> existUserOtherCompRelation = new LambdaQueryWrapper<UserOtherCompRelation>()
                    .eq(UserOtherCompRelation::getUserId, employeeId)
                    .eq(UserOtherCompRelation::getOtherCompanyId, companyIdAndDepartmentIdReqVo.getCompanyId())
                    .eq(UserOtherCompRelation::getDepartmentId, companyIdAndDepartmentIdReqVo.getDepartmentId())
                    .eq(UserOtherCompRelation::getDelFlag, false);
            if (userOtherCompRelationMapper.exists(existUserOtherCompRelation)) {
                // 如果已经存在未删除的 userId + companyId + departmentId 记录，则跳过插入，防止插入重复数据
                continue;
            }

            int insertCount = userOtherCompRelationMapper.insert(userOtherCompRelation);
            if (insertCount != 1) {
                // 如果插入失败，则抛出异常，回滚事务，并向前端返回错误提示信息
                log.error("bindCompanyAndDepartmentForEmployee, insert userOtherCompRelation failure, userOtherCompRelation: {}", userOtherCompRelation);
                throw new InsertFailureException("绑定可点餐公司失败，请稍后重试");
            }
        }
    }


    public void deleteUserOtherCompRelationById(String userOtherCompRelationId) {
        UserOtherCompRelation userOtherCompRelation = new UserOtherCompRelation();
        userOtherCompRelation.setId(userOtherCompRelationId);
        userOtherCompRelation.setDelFlag(true);
        userOtherCompRelationMapper.updateById(userOtherCompRelation);
    }


    public void updateDepartmentIdByUserOtherCompRelationId(String userOtherCompRelationId, String departmentId) {
        UserOtherCompRelation userOtherCompRelation = new UserOtherCompRelation();
        userOtherCompRelation.setId(userOtherCompRelationId);
        userOtherCompRelation.setDepartmentId(departmentId);
        userOtherCompRelationMapper.updateById(userOtherCompRelation);
    }

    public OtherCanOrderFoodCompanyCascadeRespVo queryOtherCanOrderFoodCompanyCascadeList(String companyId, String employeeId) {
        Company company = companyMapper.selectById(companyId);
        if (company == null) {
            // 如果前端传递的公司 ID 在后端查不到，直接返回空列表即可
            OtherCanOrderFoodCompanyCascadeRespVo vo = new OtherCanOrderFoodCompanyCascadeRespVo();
            vo.setCompanyList(Collections.emptyList());
            vo.setSelectedCompanyList(Collections.emptyList());
            return vo;
        }

        // 查询该租户下所有的公司列表
        String tenantId = company.getTenantId();
        LambdaQueryWrapper<Company> companyQueryWrapper = new LambdaQueryWrapper<Company>()
                .eq(Company::getTenantId, tenantId)
                // 排除当前公司，只查询租户关联的其它未删除公司信息
                .ne(Company::getId, companyId)
                .eq(Company::getDelFlag, false);
        List<Company> companyList = companyMapper.selectList(companyQueryWrapper);
        if (CollectionUtils.isEmpty(companyList)) {
            // 如果该租户下没有其它公司，则直接返回空列表即可
            OtherCanOrderFoodCompanyCascadeRespVo vo = new OtherCanOrderFoodCompanyCascadeRespVo();
            vo.setCompanyList(Collections.emptyList());
            vo.setSelectedCompanyList(Collections.emptyList());
            return vo;
        }

        List<String> companyIdList = companyList.stream().map(Company::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Department> departmentQueryWrapper = new LambdaQueryWrapper<Department>()
                .in(Department::getCompanyId, companyIdList);
        List<Department> departmentList = departmentMapper.selectList(departmentQueryWrapper);

        // 根据公司 ID 将部门信息进行分组
        Map<String, List<Department>> companyIdToDepartmentListMap = departmentList.stream().collect(Collectors.groupingBy(Department::getCompanyId));

        // 构建全部可选的公司及部门信息列表
        List<CompanyWithDepartmentInfoRespVo> companyVoList = new ArrayList<>(companyList.size());
        for (Company comp : companyList) {
            CompanyWithDepartmentInfoRespVo vo = new CompanyWithDepartmentInfoRespVo();

            vo.setCompanyId(comp.getId());
            vo.setCompanyName(comp.getName());

            List<Department> deptList = companyIdToDepartmentListMap.getOrDefault(comp.getId(), Collections.emptyList());
            List<DepartmentInfoRespVo> deptVoList = new ArrayList<>(deptList.size());
            for (Department dept : deptList) {
                DepartmentInfoRespVo deptVo = new DepartmentInfoRespVo();
                deptVo.setDepartmentId(dept.getId());
                deptVo.setDepartmentName(dept.getName());
                deptVoList.add(deptVo);
            }

            vo.setDepartmentList(deptVoList);
            companyVoList.add(vo);
        }


        // 查询当前员工已经绑定的其它可点餐公司的 ID 列表
        LambdaQueryWrapper<UserOtherCompRelation> userOtherCompRelationQueryWrapper = new LambdaQueryWrapper<UserOtherCompRelation>()
                .eq(UserOtherCompRelation::getUserId, employeeId)
                .eq(UserOtherCompRelation::getDelFlag, false);
        List<UserOtherCompRelation> userOtherCompRelationList = userOtherCompRelationMapper.selectList(userOtherCompRelationQueryWrapper);

        List<CompanyIdNameWithDepartmentIdNameRespVo> selectedCompanyVoList = new ArrayList<>(userOtherCompRelationList.size());
        if (CollectionUtils.isNotEmpty(userOtherCompRelationList)) {
            Map<String, String> companyIdToNameMap = companyList.stream().collect(Collectors.toMap(Company::getId, Company::getName));
            Map<String, String> departmentIdToNameMap = departmentList.stream().collect(Collectors.toMap(Department::getId, Department::getName));

            for (UserOtherCompRelation userOtherCompRelation : userOtherCompRelationList) {
                CompanyIdNameWithDepartmentIdNameRespVo vo = new CompanyIdNameWithDepartmentIdNameRespVo();

                String otherCompanyId = userOtherCompRelation.getOtherCompanyId();
                String otherCompanyName = companyIdToNameMap.getOrDefault(otherCompanyId, "未知");
                vo.setCompanyId(otherCompanyId);
                vo.setCompanyName(otherCompanyName);

                String departmentId = userOtherCompRelation.getDepartmentId();
                String departmentName = departmentIdToNameMap.getOrDefault(departmentId, "未知");
                vo.setDepartmentId(departmentId);
                vo.setDepartmentName(departmentName);

                selectedCompanyVoList.add(vo);
            }
        }

        OtherCanOrderFoodCompanyCascadeRespVo respVo = new OtherCanOrderFoodCompanyCascadeRespVo();
        respVo.setCompanyList(companyVoList);
        respVo.setSelectedCompanyList(selectedCompanyVoList);

        return respVo;
    }


    @Transactional(rollbackFor = Exception.class)
    public void saveCanOrderFoodCompanyForEmployee(UserOtherCompRelationCreateRespVo reqVo) {
        String employeeId = reqVo.getEmployeeId();
        User user = userMapper.selectById(employeeId);
        if (user == null) {
            // 如果前端传递过来的员工 ID 在数据库中找不到，直接返回错误提示信息即可
            log.warn("saveCanOrderFoodCompanyForEmployee, employee not exist, employeeId: {}", employeeId);
            throw new IllegalArgumentException("ID 为 " + employeeId + " 的员工信息不存在");
        }

        if (CollectionUtils.isEmpty(reqVo.getCompanyAndDepartmentIdList())) {
            // 如果前端传递过来的其它可点餐公司信息为空，设置默认值为空列表
            reqVo.setCompanyAndDepartmentIdList(Collections.emptyList());
        }

        // 1. 先删除该员工之前已经绑定的其它可点餐公司信息
        LambdaUpdateWrapper<UserOtherCompRelation> updateWrapper = new LambdaUpdateWrapper<UserOtherCompRelation>()
                .eq(UserOtherCompRelation::getUserId, employeeId)
                .eq(UserOtherCompRelation::getDelFlag, false);
        UserOtherCompRelation userOtherCompRelationDeleted = new UserOtherCompRelation();
        userOtherCompRelationDeleted.setDelFlag(true);
        userOtherCompRelationMapper.update(userOtherCompRelationDeleted, updateWrapper);

        // 2. 再插入新的其它可点餐公司信息
        for (CompanyIdAndDepartmentIdReqVo companyIdAndDepartmentIdReqVo : reqVo.getCompanyAndDepartmentIdList()) {
            UserOtherCompRelation userOtherCompRelation = new UserOtherCompRelation();
            userOtherCompRelation.setUserId(employeeId);
            userOtherCompRelation.setOtherCompanyId(companyIdAndDepartmentIdReqVo.getCompanyId());
            userOtherCompRelation.setDepartmentId(companyIdAndDepartmentIdReqVo.getDepartmentId());

            LambdaQueryWrapper<UserOtherCompRelation> existUserOtherCompRelation = new LambdaQueryWrapper<UserOtherCompRelation>()
                    .eq(UserOtherCompRelation::getUserId, employeeId)
                    .eq(UserOtherCompRelation::getOtherCompanyId, companyIdAndDepartmentIdReqVo.getCompanyId())
                    .eq(UserOtherCompRelation::getDepartmentId, companyIdAndDepartmentIdReqVo.getDepartmentId())
                    .eq(UserOtherCompRelation::getDelFlag, false);
            if (userOtherCompRelationMapper.exists(existUserOtherCompRelation)) {
                // 如果已经存在未删除的 userId + companyId + departmentId 记录，则跳过插入，防止插入重复数据
                continue;
            }

            int insertCount = userOtherCompRelationMapper.insert(userOtherCompRelation);
            if (insertCount != 1) {
                // 如果插入失败，则抛出异常，回滚事务，并向前端返回错误提示信息
                log.error("saveCanOrderFoodCompanyForEmployee, insert userOtherCompRelation failure, userOtherCompRelation: {}", userOtherCompRelation);
                throw new InsertFailureException("绑定可点餐公司失败，请稍后重试");
            }
        }
    }
}
